package com.ugoodtech.mdcc.web.service.impl;

import com.google.common.collect.Lists;
import com.mysema.query.BooleanBuilder;
import com.ugoodtech.mdcc.core.domain.PerformanceReport;
import com.ugoodtech.mdcc.core.domain.PerformanceReportDetail;
import com.ugoodtech.mdcc.core.domain.PerformanceReportRecord;
import com.ugoodtech.mdcc.core.domain.QPerformanceReport;
import com.ugoodtech.mdcc.core.domain.QPerformanceReportDetail;
import com.ugoodtech.mdcc.core.domain.User;
import com.ugoodtech.mdcc.core.domain.UserProfile;
import com.ugoodtech.mdcc.core.domain.UserType;
import com.ugoodtech.mdcc.core.repository.PerformanceReportDetailRepository;
import com.ugoodtech.mdcc.core.repository.PerformanceReportRecordRepository;
import com.ugoodtech.mdcc.core.repository.PerformanceReportRepository;
import com.ugoodtech.mdcc.core.repository.UserProfileRepository;
import com.ugoodtech.mdcc.core.repository.UserRepository;
import com.ugoodtech.mdcc.web.common.BizConstants;
import com.ugoodtech.mdcc.web.common.BizConstants.PerformancePlan;
import com.ugoodtech.mdcc.web.dto.PerformanceReportRecordDetail;
import com.ugoodtech.mdcc.web.dto.SavePerformanceData;
import com.ugoodtech.mdcc.web.exception.BizException;
import com.ugoodtech.mdcc.web.exception.EnumBizError;
import com.ugoodtech.mdcc.web.pojo.vo.PerformancePlanVO;
import com.ugoodtech.mdcc.web.service.PerformancePlanService;
import com.ugoodtech.mdcc.web.service.UserProfileService;
import com.ugoodtech.mdcc.web.utils.ExcelUtils;
import com.ugoodtech.mdcc.web.utils.PageInfoWrapper;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.hibernate.validator.constraints.NotEmpty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;

/**
 * @author dean
 * @date 2020/6/17 14:14
 */
@Service
public class PerformancePlanServiceImpl implements PerformancePlanService {

    @Autowired
    private UserProfileService userProfileService;

    @Autowired
    private PerformanceReportRepository performanceReportRepository;
    @Autowired
    private PerformanceReportDetailRepository performanceReportDetailRepository;
    @Autowired
    private PerformanceReportRecordRepository performanceReportRecordRepository;
    @Autowired
    private PerformancePlanCalculator performancePlanCalculator;

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private UserProfileRepository userProfileRepository;

    @Autowired
    private PerformancePlanRecordsFilter filter;

    private Logger log = LoggerFactory.getLogger(PerformancePlanService.class);
    @Override
    public Boolean resolvePlanExcel(MultipartFile file) {
        try {
            return resolveExcelContent(file);
        } catch (IOException e) {
            throw new BizException(e);
        }
    }

    /**
     * 获取业绩报告可以查看的年份
     *
     * @return 年份列表
     */
    @Override
    public List<Integer> getYears() {
        User currentUser = getCurrentUser();
        if (currentUser != null) {
            Long id = currentUser.getId();
            return performanceReportRepository.getYears(id);
        }else {
            return null;
        }
    }

    @Override
    public PageInfoWrapper getYearPlanPage(Integer year, String username, List<Integer> months,
                                           Integer pageIndex, Integer pageSize) {
        PerformancePlanVO yearPlan = getYearPlan(year, username, months, pageIndex, pageSize);
        PageInfoWrapper pageInfoWrapper = PerformancePlanRecordsFilter.getPageInfoThreadLocal().get();
        pageInfoWrapper.setList(yearPlan == null ? new ArrayList(0) : Arrays.asList(yearPlan));
        return pageInfoWrapper;
    }

    @Override
    public Workbook changeYear(Workbook workbook, Integer year) {
        Sheet sheet = workbook.getSheetAt(0);
        Row row = sheet.getRow(0);
        row.getCell(0).setCellValue("报告时间： " + year + "年");
        row = sheet.getRow(3);
        row.getCell(2).setCellValue(year.toString());
        row = sheet.getRow(6);
        row.getCell(2).setCellValue(year.toString());
        return workbook;
    }

    /**
     * 根据id获取某一个报告
     */
    @Override
    public PerformanceReport getPlan(Long reportId) {
        return performanceReportRepository.findOne(reportId);
    }

    public PerformancePlanVO getYearPlan(Integer year, String username, List<Integer> months,
                                         Integer pageIndex, Integer pageSize) {
        List<PerformancePlanVO> planVOList = filter.calculateHint(filter.sortData(
                filter.filterDataWhenGetYearPlan(
                                getPlan(year, username, months, pageIndex, pageSize, true,false))));
        if (CollectionUtils.isEmpty(planVOList)) {
            return null;
        }
        return planVOList.get(0);
    }

    @Override
    public PageInfoWrapper getMonthPlanPage(Integer year, String username, List<Integer> months,
                                            Integer pageIndex, Integer pageSize) {
        List<PerformancePlanVO> monthPlans = getMonthPlan(year, username, months, pageIndex, pageSize);
        PageInfoWrapper pageInfoWrapper = PerformancePlanRecordsFilter.getPageInfoThreadLocal().get();
        pageInfoWrapper.setList(CollectionUtils.isEmpty(monthPlans) ? new ArrayList(0) : monthPlans);
        return pageInfoWrapper;
    }

    @Override
    public List<PerformancePlanVO> getMonthPlan(Integer year, String username, List<Integer> months,
                                                Integer pageIndex, Integer pageSize) {
        if (log.isDebugEnabled()) {
            log.debug("Get plan of month by year [{}], username [{}] and months [{}].",
                    year, username, months);
        }
        List<PerformancePlanVO> planVOList = getPlan(year, username, months, pageIndex, pageSize, true,true);
        planVOList.forEach(planVO -> {
            PerformanceReport performanceReportDO = filter
                    .getSpecificReport(planVO.getEmployee(), planVO.getYear(),
                            PerformancePlan.OPERATION_TYPE_REALISTIC);
            if (!Objects.isNull(performanceReportDO)) {
                planVO.setMajorAreaManager(performanceReportDO.getRegionManager());
                planVO.setMinorAreaManager(performanceReportDO.getPlotManager());
            }
        });
        return filter.calculateHint(filter.filterDataWhenGetMonthPlan(filter.sortData(planVOList)));
    }

    private Boolean resolveExcelContent(MultipartFile file) throws IOException {
        Workbook workbook = new XSSFWorkbook(file.getInputStream());
        Sheet sheet = workbook.getSheetAt(0);
        int performancePlanSize = getPerformancePlanSize(sheet);
        List<SavePerformanceData> savePerformanceDatas =new ArrayList<>();
        for (int index = 0; index < performancePlanSize; index++) {
            String employee = getEmployee(sheet,index);
            List<UserProfile> userProfiles = userProfileRepository.findByRealNameAndDeletedFalse(employee);
            if (userProfiles.size()==0){
                throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("工作人员" + employee + "不存在"));
            }
            if (userProfiles.size() > 1) {
                throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg(employee + ", 有重名人员"));
            }
            User userByName =userProfiles.get(0).getUser();
            if (!Objects.equals(userByName.getUserType(), UserType.dealers) && !Objects.equals(userByName.getUserType(), UserType.insiders) ) {
                throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("工作人员" + employee + "不存在"));
            }
//        employee = userService.getUserProfile(userByName.getId()).getUsername();
            int year = getYear(sheet);
            if (log.isDebugEnabled()) {
                log.debug("Extracting data of forecast from excel.");
            }
            List<BigDecimal> VRPCollectionValue = getForecastValueOfMonths(sheet, PerformancePlan.VRP,
                    PerformancePlan.PROJECT_COLLECTION,index);
            List<BigDecimal> VRPNotCollectionValue = getForecastValueOfMonths(sheet, PerformancePlan.VRP,
                    PerformancePlan.PROJECT_NOT_COLLECTION,index);
            List<BigDecimal> WandaCollectionValue = getForecastValueOfMonths(sheet, PerformancePlan.WAN_DA,
                    PerformancePlan.PROJECT_COLLECTION,index);
            List<BigDecimal> WandaNotCollectionValue = getForecastValueOfMonths(sheet,
                    PerformancePlan.WAN_DA, PerformancePlan.PROJECT_NOT_COLLECTION,index);
            SavePerformanceData savePerformanceData = storeExcelValue(year, userProfiles.get(0).getRealName(), PerformancePlan.OPERATION_TYPE_PLAN, VRPCollectionValue,
                    VRPNotCollectionValue, WandaCollectionValue, WandaNotCollectionValue);
            savePerformanceDatas.add(savePerformanceData);
        }
        for (SavePerformanceData savePerformanceData : savePerformanceDatas) {
            PerformanceReport performanceReport = savePerformanceData.getPerformanceReport();
            PerformanceReport save = performanceReportRepository.save(performanceReport);
            PerformanceReportRecord performanceReportRecord = savePerformanceData.getPerformanceReportRecordDetail().getPerformanceReportRecord();
            performanceReportRecord.setPerformanceReport(save);
            performanceReportRecordRepository.save(performanceReportRecord);
            List<PerformanceReportDetail> performanceReportDetails = savePerformanceData.getPerformanceReportRecordDetail().getPerformanceReportDetails();
            for (PerformanceReportDetail performanceReportDetail : performanceReportDetails) {
                performanceReportDetail.setPerformanceReport(save);
                performanceReportDetailRepository.save(performanceReportDetail);
            }
        }
        return true;
    }
    private int getPerformancePlanSize(Sheet sheet){
        //前三行为title不计入
        int lastRowNum = sheet.getLastRowNum();
        int i = (sheet.getLastRowNum() - 2) % 6;
        if ((sheet.getLastRowNum() - 2) % 6 > 0){//6行为一组数据 如果有余数说明行数不对报错
            throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("上传数据有误，行数计算错误"));
        }
        return (sheet.getLastRowNum()-2)/6;
    }

    private String getEmployee(Sheet sheet,int index) {
        Cell cell = ExcelUtils.getCell(sheet, 0, 3 + index * 6);
        if (Objects.equals(cell.getCellTypeEnum(), CellType._NONE)) {
            return null;
        }
        cell.setCellType(XSSFCell.CELL_TYPE_STRING);
        return cell.getStringCellValue();
    }
    private Integer getYear(Sheet sheet) {
        String year = ExcelUtils.convertToString(ExcelUtils.getCell(sheet, 0, 0));
        String yearOfVRP = ExcelUtils.convertToString(ExcelUtils.getCell(sheet, 2, 3));
        String yearOfWanda = ExcelUtils.convertToString(ExcelUtils.getCell(sheet, 2, 6));
        try {
            year = year.substring(6, 10);
            if (!Objects.equals(year, yearOfVRP) || !Objects.equals(year, yearOfWanda)) {
                throw new IllegalArgumentException("年份格式错误");
            }
            if (!StringUtils.isNumeric(year)) {
                throw new IllegalArgumentException("年份格式错误");
            }
        } catch (StringIndexOutOfBoundsException e) {
            throw new IllegalArgumentException("年份格式错误");
        }
        return Integer.valueOf(year);
    }

    public List<PerformancePlanVO> getPlan(Integer year, String username, List<Integer> months,
                                           Integer pageIndex, Integer pageSize, boolean latest,boolean isMonths) {
        if (log.isDebugEnabled()) {
            log.debug("Get plan of [{}] in months of [{}] in [{}].", username, months, year);
        }
        // 默认取今年的数据
        if (Objects.isNull(year)) {
            year = Calendar.getInstance().get(Calendar.YEAR);
        }
        // Filter all data belonging to username of year and last of that year.
        List<PerformanceReportDetail> performanceReportDetailDOList = filter
                .filterRecords(username, Arrays.asList(year, year - 1), year, months, pageIndex, pageSize,isMonths);
        // Separate performance plan detail by username and year.
        Map<String, List<PerformanceReportDetail>> detailGroupByUsername = groupDataUsername(pageSize,
                performanceReportDetailDOList, year);
        // Convert data of each user to plan vo.
        List<PerformancePlanVO> performancePlanVOList = new ArrayList<>(detailGroupByUsername.size());
        for (Map.Entry<String, List<PerformanceReportDetail>> planGroupSignListEntry
                : detailGroupByUsername.entrySet()) {
            PerformancePlanVO planVO = performancePlanCalculator
                    .convertValuesList(planGroupSignListEntry.getValue(), year);
            // Get report of plan type and fill extra data in PerformancePlanVO.
            PerformanceReport performanceReportDO = filter
                    .getSpecificReport(planGroupSignListEntry.getKey(), year,
                            PerformancePlan.OPERATION_TYPE_PLAN);
            // Get forecast report to add major.
            PerformanceReport forecastReport = filter
                    .getSpecificReport(planGroupSignListEntry.getKey(), year,
                            PerformancePlan.OPERATION_TYPE_FORECAST);
            planVO.setYear(year);
            planVO.setEmployee(planGroupSignListEntry.getKey());
            if (!Objects.isNull(forecastReport)) {
                planVO.setMajorAreaManager(forecastReport.getRegionManager());
                planVO.setMinorAreaManager(forecastReport.getPlotManager());
            }
            if (performanceReportDO != null) {
                planVO.setImportUser(performanceReportDO.getUserName());
                planVO.setImportTime(performanceReportDO.getUpdateTime());
            }
            performancePlanVOList.add(planVO);
        }
        if (latest) {
            filter.filterLatestData(performancePlanVOList);
        }
        return performancePlanVOList;
    }

    private List<BigDecimal> getForecastValueOfMonths(Sheet sheet, Integer brandType,
                                                      Integer clientType,int index) {
        List<BigDecimal> valueList = new ArrayList<>(12);
        for (int i = 1; i <= 12; i++) {
            valueList.add(getForecastValue(sheet, brandType, clientType, i,index));
        }
        return valueList;
    }
    /**
     * 检查数值是否大于0
     */
    private BigDecimal checkValue(BigDecimal value) {
        if (Objects.isNull(value)) {
            return null;
        }
        if (BigDecimal.ZERO.compareTo(value) > 0) {
            throw new IllegalArgumentException("数据错误");
        }
        return value;
    }
    /**
     * 获取某月某个类型(计划)某个品牌的值
     */
    private BigDecimal getForecastValue(Sheet sheet, Integer brandType, Integer clientType,
                                        Integer month ,int index) {
        Cell cell = ExcelUtils
                .getCell(sheet, month + 4, PerformancePlan.getBrandLocationInExcel(brandType,index) + clientType);
        if (Objects.equals(cell.getCellTypeEnum(), CellType._NONE)
                || Objects.equals(cell.getCellTypeEnum(), CellType.BLANK)) {
            return null;
        }
        return checkValue(new BigDecimal(ExcelUtils.convertToString(cell)));
    }
    @Transactional(rollbackFor = Exception.class)
    public SavePerformanceData storeExcelValue(@NotNull Integer year, @NotEmpty String employee,
                                               @NotNull Integer operationType,
                                               List<BigDecimal> VRPCollectionValue, List<BigDecimal> VRPNotCollectionValue,
                                               List<BigDecimal> WandaCollectionValue, List<BigDecimal> WandaNotCollectionValue) {
        if (log.isDebugEnabled()) {
            log.debug("Store data of [{}] in [{}] into db.", employee, year);
        }
        // 获取之前这种类型的报告
        PerformanceReport performanceReportDO = getPreviousExistingReport(year, employee,
                operationType);
        // 查找employee
        List<UserProfile> userProfiles = userProfileRepository.findByRealNameAndDeletedFalse(employee);
        if (userProfiles.size()>1){
            throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg(employee + ", 有重名人员"));
        }
        if (userProfiles.size()==0){
            throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg(employee + ", 不存在"));
        }
        User user =userProfiles.get(0).getUser();
        performanceReportDO = updateReportVersion(performanceReportDO, employee, user, year,
                PerformancePlan.OPERATION_TYPE_PLAN, null, null);
        PerformanceReportRecordDetail performanceReportDetails = storeRecords(performanceReportDO, year, employee, operationType,
                VRPCollectionValue, VRPNotCollectionValue, WandaCollectionValue, WandaNotCollectionValue);
        SavePerformanceData  savePerformanceData=new SavePerformanceData();
        savePerformanceData.setPerformanceReport(performanceReportDO);
        savePerformanceData.setPerformanceReportRecordDetail(performanceReportDetails);
        return savePerformanceData;
//        performanceReportRepository.save(performanceReportDO);
    }
    /**
     * 更新报告版本号
     */
    @SuppressWarnings("all")
    private PerformanceReport updateReportVersion(PerformanceReport previousPerformanceReportDO,
                                                  String employee, User user, Integer year, Integer operationType,
                                                  UserProfile regionManager, UserProfile plotManager) {
        PerformanceReport performanceReportDO;
        Date date = Calendar.getInstance().getTime();
        User userProfileDO =getCurrentUser();
        PerformanceReport save;
        if (Objects.isNull(previousPerformanceReportDO)) {
            // 以前不存在报告, 插入新的记录
            if ((Objects.isNull(regionManager) || Objects.isNull(plotManager))
                    && operationType != PerformancePlan.OPERATION_TYPE_PLAN) {
                throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("请输入大区小区经理"));
            }
            performanceReportDO = new PerformanceReport();
            performanceReportDO.setEmployeeName(employee);
            performanceReportDO.setYear(year);
            performanceReportDO.setVersion(PerformancePlan.INITIAL_VERSION);
            performanceReportDO.setStatus(operationType);
            performanceReportDO.setUserId(user.getId());
            if (!Objects.equals(operationType, PerformancePlan.OPERATION_TYPE_PLAN)) {
                performanceReportDO.setRegionManager(regionManager.getRealName());
                performanceReportDO.setRegionManagerId(regionManager.getUser().getId());
                performanceReportDO.setPlotManager(plotManager.getRealName());
                performanceReportDO.setPlotManagerId(plotManager.getUser().getId());
            }
            performanceReportDO.setCreateTime(date);
            performanceReportDO.setUpdateTime(date);
            if (userProfileDO != null) {
                UserProfile currentUserProfile = userProfileRepository.findByUserId(userProfileDO.getId());
                performanceReportDO.setUserId(userProfileDO.getId());
                performanceReportDO.setUserName(currentUserProfile.getRealName());
            }else {
                log.debug("currentUser为空");
                UserProfile currentUserProfile = userProfileRepository.findByUserId(user.getId());
                performanceReportDO.setUserId(user.getId());
                performanceReportDO.setUserName(currentUserProfile.getRealName());
            }

            if (log.isDebugEnabled()) {
                log.debug("存储报告记录: [{}].", performanceReportDO);
            }
//            save = performanceReportRepository.save(performanceReportDO);
        } else {
            // 之前存在相同的报告, 更新报告版本
            performanceReportDO =  previousPerformanceReportDO;
            performanceReportDO.setEmployeeName(employee);
            if (userProfileDO != null) {
                UserProfile currentUserProfile = userProfileRepository.findByUserId(userProfileDO.getId());
                performanceReportDO.setUserName(currentUserProfile.getRealName());
            }else {
                log.debug("currentUser为空");
                UserProfile currentUserProfile = userProfileRepository.findByUserId(user.getId());
                performanceReportDO.setUserName(currentUserProfile.getRealName());
            }
            performanceReportDO.setId(previousPerformanceReportDO.getId());
            performanceReportDO.setVersion(previousPerformanceReportDO.getVersion() + 1);
            performanceReportDO.setUpdateTime(date);
        }
        return performanceReportDO;
    }
    /**
     * 查看该用户是否存在某年的某类型报告
     */
    private PerformanceReport getPreviousExistingReport(Integer year, String employee,
                                                          Integer operationType) {
//        PerformanceReportDOExample example = new PerformanceReportDOExample();
//        example.or().andYearEqualTo(year).andEmployeeNameEqualTo(employee)
//                .andStatusEqualTo(operationType);
        QPerformanceReport qPerformanceReport = QPerformanceReport.performanceReport;
        BooleanBuilder builder = new BooleanBuilder();
        builder.and(qPerformanceReport.year.eq(year)).and(qPerformanceReport.employeeName.eq(employee))
                .and(qPerformanceReport.status.eq(operationType));
        Iterable<PerformanceReport> all = performanceReportRepository.findAll(builder);
        ArrayList<PerformanceReport> performanceReportDOList = Lists.newArrayList(all);
        if (CollectionUtils.isEmpty(performanceReportDOList)) {
            return null;
        } else {
            if (performanceReportDOList.size() > 1) {
                throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("数据历史信息错误, 请联系管理员"));
            }
            return performanceReportDOList.get(0);
        }
    }
    /**
     * 插入数据库记录
     *
     * @param performanceReportDO 之前存在的相应类型的报告
     */
    private  PerformanceReportRecordDetail storeRecords(PerformanceReport performanceReportDO, @NotNull Integer year,
                              @NotEmpty String employee, @NotNull Integer operationType,
                              List<BigDecimal> VRPCollectionValue, List<BigDecimal> VRPNotCollectionValue,
                              List<BigDecimal> WandaCollectionValue, List<BigDecimal> WandaNotCollectionValue) {

        boolean notModified = true;
        // 获取预测和实际数据, 用于后续数据校验
        PerformanceReport realisticData = null;
        PerformanceReport planData = null;
        if (Objects.equals(operationType, PerformancePlan.OPERATION_TYPE_FORECAST)) {
            realisticData = getPreviousExistingReport(year, employee,
                    PerformancePlan.OPERATION_TYPE_REALISTIC);
            planData = getPreviousExistingReport(year, employee, PerformancePlan.OPERATION_TYPE_PLAN);
        }
        PerformanceReport forecastData = null;
        if (Objects.equals(operationType, PerformancePlan.OPERATION_TYPE_REALISTIC)) {
            forecastData = getPreviousExistingReport(year, employee,
                    PerformancePlan.OPERATION_TYPE_FORECAST);
        }
        List<PerformanceReportDetail> performanceReportDetailDOList = new ArrayList<>(48);
        if (storeRecords(VRPCollectionValue, performanceReportDetailDOList, performanceReportDO,
                year, employee, operationType, PerformancePlan.PROJECT_COLLECTION, PerformancePlan.VRP,
                realisticData, forecastData, planData)) {
            notModified = false;
        }
        if (storeRecords(VRPNotCollectionValue, performanceReportDetailDOList,
                performanceReportDO, year, employee, operationType, PerformancePlan.PROJECT_NOT_COLLECTION,
                PerformancePlan.VRP, realisticData, forecastData, planData)) {
            notModified = false;
        }
        if (storeRecords(WandaCollectionValue, performanceReportDetailDOList, performanceReportDO,
                year, employee, operationType, PerformancePlan.PROJECT_COLLECTION,
                PerformancePlan.WAN_DA, realisticData, forecastData, planData)) {
            notModified = false;
        }
        if (storeRecords(WandaNotCollectionValue, performanceReportDetailDOList,
                performanceReportDO, year, employee, operationType, PerformancePlan.PROJECT_NOT_COLLECTION,
                PerformancePlan.WAN_DA, realisticData, forecastData, planData)) {
            notModified = false;
        }
        if (notModified) {
            throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("该报告与上次提交报告相比无修改内容"));
        }
            PerformanceReportRecord performanceReportRecord = addPerformPlanRecord(operationType, employee, performanceReportDO.getUserName(),
                    performanceReportDO, performanceReportDO.getVersion());
//       for (PerformanceReportDetail performanceReportDetail : performanceReportDetailDOList) {
//            PerformanceReportDetail save = performanceReportDetailRepository.save(performanceReportDetail);
//            if (save == null) {
//                throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("数据错误"));
//            }
//        }
        PerformanceReportRecordDetail performanceReportRecordDetail =new PerformanceReportRecordDetail();
        performanceReportRecordDetail.setPerformanceReportDetails(performanceReportDetailDOList);
        performanceReportRecordDetail.setPerformanceReportRecord(performanceReportRecord);
        return performanceReportRecordDetail;
//        int rows = performanceReportDetailDOMapperExt.batchInsert(performanceReportDetailDOList);
//        if (rows != 48) {
//            throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("数据错误"));
//        }
    }
    /**
     * 生成数据库记录
     *
     * @param realisticReport 实际业绩报告一览, null表示不存在相应年份实际数据
     * @param forecastReport 预测业绩报告一览
     */
    @Transactional(rollbackFor = Exception.class)
    boolean storeRecords(List<BigDecimal> values,
                                List<PerformanceReportDetail> performanceReportDetailDOListToInsert,
                                PerformanceReport performanceReportDO, @NotNull Integer year, @NotEmpty String employee,
                                @NotNull Integer operationType, Integer clientType, Integer brandType,
                                PerformanceReport realisticReport, PerformanceReport forecastReport,
                                PerformanceReport planData) {
        Date date = Calendar.getInstance().getTime();
        // 判断是否是第一份报告, 再去查找历史报告记录用于比对
        List<PerformanceReportDetail> performanceReportDetailDOList = null;
        if (performanceReportDO.getVersion() != 0) {
            performanceReportDetailDOList = getRecords(performanceReportDO.getId(),
                    performanceReportDO.getVersion() - 1, clientType, brandType);
        }
        checkForecastData(operationType, clientType, brandType, realisticReport, planData, values);
        checkRealisticData(operationType, clientType, brandType, forecastReport, values);
        // 对数据进行比对, 判断是否有更改的内容
        BigDecimal value = null;
        boolean isModified = false;
        for (int i = 0, j = values.size(); i < j; i++) {
            value = values.get(i);
            PerformanceReportDetail performanceReportDetailDO = new PerformanceReportDetail();
            // 和上次报告进行数据比对, 查看是否修改了数据
            if (!Objects.isNull(performanceReportDetailDOList)) {
                if (!Objects.isNull(performanceReportDetailDOList.get(i).getSales()) && !Objects
                        .isNull(value)) {
                    if (performanceReportDetailDOList.get(i).getSales().compareTo(value) != 0) {
                        performanceReportDetailDO.setIsModified(1);
                        if (!isModified) {
                            isModified = true;
                        }
                    }
                } else {
                    if (!Objects.isNull(performanceReportDetailDOList.get(i).getSales()) || !Objects
                            .isNull(value)) {
                        performanceReportDetailDO.setIsModified(1);
                        if (!isModified) {
                            isModified = true;
                        }
                    }
                }
            } else {
                if (!isModified) {
                    isModified = true;
                }
                performanceReportDetailDO.setIsModified(0);
            }
            performanceReportDetailDO.setVersion(performanceReportDO.getVersion());
            performanceReportDetailDO.setSales(value);
            performanceReportDetailDO.setEmployeeName(employee);
            performanceReportDetailDO.setStatus(operationType);
            performanceReportDetailDO.setYear(year);
            performanceReportDetailDO.setBrandType(brandType);
            performanceReportDetailDO.setCustomerType(clientType);
            performanceReportDetailDO.setMonth(i + 1);
//            performanceReportDetailDO.setPerformanceReportId(performanceReportDO.getId());
            performanceReportDetailDO.setPerformanceReport(performanceReportDO);
            performanceReportDetailDO.setIsDeleted(0);
            performanceReportDetailDO.setCreateTime(date);
            performanceReportDetailDO.setUpdateTime(date);
            performanceReportDetailDOListToInsert.add(performanceReportDetailDO);
        }
        return isModified;
    }
    /**
     * 获取某个版本, 某个常规报告, 客户类型和品牌类型的数据
     *
     * @param reportId 常规报告id
     * @param version 版本号
     * @param clientType 客户类型
     * @param brandType 品牌类型
     * @return 相应业绩报告数据
     */
    private List<PerformanceReportDetail> getRecords(Long reportId, Integer version,
                                                       Integer clientType, Integer brandType) {
        if (log.isDebugEnabled()) {
            log.debug("Get report of version [{}] by report id [{}].", version, reportId);
        }
        QPerformanceReportDetail qPerformanceReportDetail =QPerformanceReportDetail.performanceReportDetail;
        BooleanBuilder builder = new BooleanBuilder();
        builder.and(qPerformanceReportDetail.version.eq(version)).
                and(qPerformanceReportDetail.performanceReport.id.eq(reportId)).
                and(qPerformanceReportDetail.customerType.eq(clientType)).
                and(qPerformanceReportDetail.brandType.eq(brandType));
        Pageable pageables=new PageRequest(0, 1000000,
                new Sort(Sort.Direction.ASC, "month"));
        Page<PerformanceReportDetail> all = performanceReportDetailRepository.findAll(builder, pageables);
//        example.setOrderByClause("month asc");
//        example.or().andVersionEqualTo(version).andPerformanceReportIdEqualTo(reportId)
//                .andCustomerTypeEqualTo(clientType).andBrandTypeEqualTo(brandType);
        List<PerformanceReportDetail> performanceReportDetailDOList =  all.getContent();
        if (performanceReportDetailDOList.size() != 12) {
            throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("报告数据错误"));
        }
        return performanceReportDetailDOList;
    }
    /**
     * 当前编辑信息为预测时, 查看是否有实际的数据 在某月的实际数据存在但是当前预测编辑数据中相应月份的预测数据不存在时则无法编辑
     *
     * @param operationType 操作类型, 预测实际
     * @param clientType 客户类型
     * @param brandType 品牌类型
     * @param realisticReport 实际报告
     * @param values 当前插入数据
     */
    private void checkForecastData(@NotNull Integer operationType, Integer clientType,
                                   Integer brandType, PerformanceReport realisticReport, PerformanceReport planData,
                                   List<BigDecimal> values) {
        if (Objects.equals(operationType, PerformancePlan.OPERATION_TYPE_FORECAST)) {
            if (Objects.isNull(planData)) {
                throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("请先填写计划数据"));
            } else {
                List<PerformanceReportDetail> planReportData = getRecords(planData.getId(),
                        planData.getVersion(), clientType, brandType);
                for (int i = 0; i < 12; i++) {
                    if (Objects.isNull(planReportData.get(i).getSales()) && !Objects.isNull(values.get(i))) {
                        throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("有月份无计划销售指标，请重新填写"));
                    }
                }
            }
        }
        if (Objects.equals(operationType, PerformancePlan.OPERATION_TYPE_FORECAST)
                && !Objects.isNull(realisticReport)) {
            List<PerformanceReportDetail> realisticReportData = getRecords(realisticReport.getId(),
                    realisticReport.getVersion(), clientType, brandType);
            for (int i = 0; i < 12; i++) {
                if (!Objects.isNull(realisticReportData.get(i).getSales())
                        && Objects.isNull(values.get(i))) {
                    throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("该字段已有实际销售指标，不可清空"));
                }
            }
        }
    }
    /**
     * 添加业绩报告记录
     *
     * @param operationType 操作类型 计划预测实际
     * @param employeeName 工作人员名称
     * @param operatorName 操作人员名称
     * @param report 报告
     * @param version 报告版本
     */
    public PerformanceReportRecord addPerformPlanRecord(Integer operationType, String employeeName, String operatorName,
                                     PerformanceReport report, Integer version) {
        PerformanceReportRecord reportRecordDO = new PerformanceReportRecord();
        Date date = Calendar.getInstance().getTime();
        reportRecordDO.setCreateTime(date);
        reportRecordDO.setUpdateTime(date);
        reportRecordDO.setEmployeeName(employeeName);
        reportRecordDO.setOperaterName(operatorName);
        reportRecordDO.setStatus(operationType);
        reportRecordDO.setPerformanceReport(report);
        reportRecordDO.setVersion(version);
        reportRecordDO.setIsDeleted(0);
        reportRecordDO.setOperationTime(date);
        if (log.isDebugEnabled()) {
            log.debug("Insert performance operation record [{}].", reportRecordDO);
        }
        return reportRecordDO;
//        PerformanceReportRecord save = performanceReportRecordRepository.save(reportRecordDO);
//        if (save ==null) {
//            throw new BizException(EnumBizError.OPERATION_FAIL.setDetailErrMsg("添加操作记录失败"));
//        }
    }
    /**
     * Separate performance plan detail by username and year.
     */
    private Map<String, List<PerformanceReportDetail>> groupDataUsername(Integer pageSize,
                                                                           List<PerformanceReportDetail> performanceReportDetailDOList, Integer year) {
        Map<String, List<PerformanceReportDetail>> detailGroupByUsername = new HashMap<>(
                pageSize);
        performanceReportDetailDOList.forEach(performanceReportDetailDO -> {
            List<PerformanceReportDetail> reportDetailDOList = detailGroupByUsername.computeIfAbsent(
                    performanceReportDetailDO.getEmployeeName(), k -> new ArrayList<>());
            reportDetailDOList.add(performanceReportDetailDO);
        });
        // 对于某个人的数据中，有去年的数据但是没有今年的数据则将其这个人的所有数据过滤掉
        Map<String, List<PerformanceReportDetail>> detailGroupByUsernameAfterFilter = new HashMap<>(
                detailGroupByUsername.size());
        for (Map.Entry<String, List<PerformanceReportDetail>> planGroupSignListEntry
                : detailGroupByUsername.entrySet()) {
            Set<Integer> yearSet = new HashSet<>(2);
            for (PerformanceReportDetail performanceReportDetailDO : planGroupSignListEntry
                    .getValue()) {
                yearSet.add(performanceReportDetailDO.getYear());
            }
            // 如果有今年的数据, 则将其返回, 否则过滤掉
            if (yearSet.contains(year)) {
                detailGroupByUsernameAfterFilter
                        .put(planGroupSignListEntry.getKey(), planGroupSignListEntry.getValue());
            }
        }
        return detailGroupByUsernameAfterFilter;
    }

    /**
     * 在编辑或添加实际数据时, 需要保证在相应月份的预测数据填写后才能填写某月的实际数据
     *
     * @param operationType 操作类型, 预测实际
     * @param clientType 客户类型
     * @param brandType 品牌类型
     * @param forecastReport 预测报告
     * @param values 当前插入数据
     */
    private void checkRealisticData(@NotNull Integer operationType, Integer clientType,
                                    Integer brandType, PerformanceReport forecastReport,
                                    List<BigDecimal> values) {
        // 在编辑或添加实际数据时, 需要保证在相应月份的预测数据填写后才能填写某月的实际数据
        if (Objects.equals(operationType, PerformancePlan.OPERATION_TYPE_REALISTIC)) {
            if (Objects.isNull(forecastReport)) {
                throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("预测数据未填写, 请先填写预测数据"));
            }
            // 获取相应年份的预测数据
            List<PerformanceReportDetail> forecastReportData = getRecords(forecastReport.getId(),
                    forecastReport.getVersion(), clientType, brandType);
            for (int i = 0; i < 12; i++) {
                if (Objects.isNull(forecastReportData.get(i).getSales())
                        && !Objects.isNull(values.get(i))) {
                    throw new BizException(EnumBizError.OPERATION_FAIL.setErrMsg("有月份无预测销售指标，请重新填写"));
                }
            }
        }
    }



    User getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = authentication.getPrincipal();
        if (principal != null && principal instanceof User) {
            return (User) principal;
        } else {
            Object details = authentication.getDetails();
            if (details != null && details instanceof User) {
                return (User) details;
            }
        }
        return null;
    }
}
